// 版权所有2010 Go作者。保留所有权利。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

package image

import (
	"image/color"
	"math/bits"
	"strconv"
)

// 点是X，Y坐标对。轴向右和向下增加。
type Point struct {
	X, Y int
}

// String返回p的字符串表示形式，如“（3,4）”。
func (p Point) String() string {
	return "(" + strconv.Itoa(p.X) + "," + strconv.Itoa(p.Y) + ")"
}

// Add返回向量p+q。
func (p Point) Add(q Point) Point {
	return Point{p.X + q.X, p.Y + q.Y}
}

// Sub返回向量p-q。
func (p Point) Sub(q Point) Point {
	return Point{p.X - q.X, p.Y - q.Y}
}

// Mul返回向量p*k。
func (p Point) Mul(k int) Point {
	return Point{p.X * k, p.Y * k}
}

// Div返回向量p/k。
func (p Point) Div(k int) Point {
	return Point{p.X / k, p.Y / k}
}

// 在报告p是否在r中。
func (p Point) In(r Rectangle) bool {
	return r.Min.X <= p.X && p.X < r.Max.X &&
		r.Min.Y <= p.Y && p.Y < r.Max.Y
}

// Mod返回r中的点q，使得p.X-q.X是r宽度的倍数
// 而p.Y-q.Y是r高度的倍数。
func (p Point) Mod(r Rectangle) Point {
	w, h := r.Dx(), r.Dy()
	p = p.Sub(r.Min)
	p.X = p.X % w
	if p.X < 0 {
		p.X += w
	}
	p.Y = p.Y % h
	if p.Y < 0 {
		p.Y += h
	}
	return p.Add(r.Min)
}

// Eq报告p和q是否相等。
func (p Point) Eq(q Point) bool {
	return p == q
}

// ZP是零点。
// 
// 不推荐：使用文字图像。而是点{}。
var ZP Point

// Pt是点{X，Y}的简写。
func Pt(X, Y int) Point {
	return Point{X, Y}
}

// 一个矩形包含最小X<=X<Max.X，最小Y<=Y<Max.Y的点。
// 如果最小X<=Max.X，则格式良好，同样地，对于Y，点始终格式良好。矩形的方法总是为
// 格式良好的输入返回格式良好的输出。
// 
// 矩形也是一个以矩形本身为边界的图像。在
// 返回颜色。对于矩形和颜色中的点不透明。透明
// 否则。
type Rectangle struct {
	Min, Max Point
}

// String返回类似于“（3,4）-（6,5）”的r的字符串表示形式。
func (r Rectangle) String() string {
	return r.Min.String() + "-" + r.Max.String()
}

// Dx返回r的宽度。
func (r Rectangle) Dx() int {
	return r.Max.X - r.Min.X
}

// Dy返回r的高度。
func (r Rectangle) Dy() int {
	return r.Max.Y - r.Min.Y
}

// Size返回r的宽度和高度。
func (r Rectangle) Size() Point {
	return Point{
		r.Max.X - r.Min.X,
		r.Max.Y - r.Min.Y,
	}
}

// Add返回按p转换的矩形r。
func (r Rectangle) Add(p Point) Rectangle {
	return Rectangle{
		Point{r.Min.X + p.X, r.Min.Y + p.Y},
		Point{r.Max.X + p.X, r.Max.Y + p.Y},
	}
}

// Sub返回按-p转换的矩形r。
func (r Rectangle) Sub(p Point) Rectangle {
	return Rectangle{
		Point{r.Min.X - p.X, r.Min.Y - p.Y},
		Point{r.Max.X - p.X, r.Max.Y - p.Y},
	}
}

// Inset返回按n插入的矩形r，可以是负数。如果r的任意一个尺寸小于2*n，则返回r的中心附近的一个空矩形。
func (r Rectangle) Inset(n int) Rectangle {
	if r.Dx() < 2*n {
		r.Min.X = (r.Min.X + r.Max.X) / 2
		r.Max.X = r.Min.X
	} else {
		r.Min.X += n
		r.Max.X -= n
	}
	if r.Dy() < 2*n {
		r.Min.Y = (r.Min.Y + r.Max.Y) / 2
		r.Max.Y = r.Min.Y
	} else {
		r.Min.Y += n
		r.Max.Y -= n
	}
	return r
}

// Intersect返回r和s所包含的最大矩形。如果
// 两个矩形不重叠，则返回零矩形。
func (r Rectangle) Intersect(s Rectangle) Rectangle {
	if r.Min.X < s.Min.X {
		r.Min.X = s.Min.X
	}
	if r.Min.Y < s.Min.Y {
		r.Min.Y = s.Min.Y
	}
	if r.Max.X > s.Max.X {
		r.Max.X = s.Max.X
	}
	if r.Max.Y > s.Max.Y {
		r.Max.Y = s.Max.Y
	}
	// 让r0和s0为调用方法
	// 时r和s的值，下一行相当于：
	// 
	// 如果max（r0.Min.X，s0.Min.X）>=Min（r0.max.X，s0.max.X）| | likewisefy{etc}
	if r.Empty() {
		return ZR
	}
	return r
}

// Union返回同时包含r和s的最小矩形。
func (r Rectangle) Union(s Rectangle) Rectangle {
	if r.Empty() {
		return s
	}
	if s.Empty() {
		return r
	}
	if r.Min.X > s.Min.X {
		r.Min.X = s.Min.X
	}
	if r.Min.Y > s.Min.Y {
		r.Min.Y = s.Min.Y
	}
	if r.Max.X < s.Max.X {
		r.Max.X = s.Max.X
	}
	if r.Max.Y < s.Max.Y {
		r.Max.Y = s.Max.Y
	}
	return r
}

// 空报告矩形是否不包含点。
func (r Rectangle) Empty() bool {
	return r.Min.X >= r.Max.X || r.Min.Y >= r.Max.Y
}

// Eq报告r和s是否包含相同的点集。所有空的
// 矩形被认为是相等的。
func (r Rectangle) Eq(s Rectangle) bool {
	return r == s || r.Empty() && s.Empty()
}

// 重叠报告r和s是否有非空交点。
func (r Rectangle) Overlaps(s Rectangle) bool {
	return !r.Empty() && !s.Empty() &&
		r.Min.X < s.Max.X && s.Min.X < r.Max.X &&
		r.Min.Y < s.Max.Y && s.Min.Y < r.Max.Y
}

// 在报告中，r中的每个点是否都在s中。
func (r Rectangle) In(s Rectangle) bool {
	if r.Empty() {
		return true
	}
	// 请注意，r.Max是r的独占绑定，因此r.In（s）
	// 不要求r.Max.In（s）。
	return s.Min.X <= r.Min.X && r.Max.X <= s.Max.X &&
		s.Min.Y <= r.Min.Y && r.Max.Y <= s.Max.Y
}

// 佳能返回r的规范版本。返回的矩形具有最小
// 和最大坐标，如果需要，可以进行交换，以使其格式良好。
func (r Rectangle) Canon() Rectangle {
	if r.Max.X < r.Min.X {
		r.Min.X, r.Max.X = r.Max.X, r.Min.X
	}
	if r.Max.Y < r.Min.Y {
		r.Min.Y, r.Max.Y = r.Max.Y, r.Min.Y
	}
	return r
}

// At实现图像接口。
func (r Rectangle) At(x, y int) color.Color {
	if (Point{x, y}).In(r) {
		return color.Opaque
	}
	return color.Transparent
}

// RGBA64At实现RGBA64Image接口。
func (r Rectangle) RGBA64At(x, y int) color.RGBA64 {
	if (Point{x, y}).In(r) {
		return color.RGBA64{0xffff, 0xffff, 0xffff, 0xffff}
	}
	return color.RGBA64{}
}

// Bounds实现图像接口。
func (r Rectangle) Bounds() Rectangle {
	return r
}

// ColorModel实现图像接口。
func (r Rectangle) ColorModel() color.Model {
	return color.Alpha16Model
}

// ZR是零矩形。
// 
// 已弃用：使用文字图像。而是矩形{}。
var ZR Rectangle

// Rect是矩形{Pt（x0，y0），Pt（x1，y1）}的缩写。返回的
// 矩形在必要时交换了最小和最大坐标，以便
// 格式正确。
func Rect(x0, y0, x1, y1 int) Rectangle {
	if x0 > x1 {
		x0, x1 = x1, x0
	}
	if y0 > y1 {
		y0, y1 = y1, y0
	}
	return Rectangle{Point{x0, y0}, Point{x1, y1}}
}

// mul3noneng返回（x*y*z），除非至少有一个参数为负，或者如果计算溢出int类型，则返回-1。
func mul3NonNeg(x int, y int, z int) int {
	if (x < 0) || (y < 0) || (z < 0) {
		return -1
	}
	hi, lo := bits.Mul64(uint64(x), uint64(y))
	if hi != 0 {
		return -1
	}
	hi, lo = bits.Mul64(lo, uint64(z))
	if hi != 0 {
		return -1
	}
	a := int(lo)
	if (a < 0) || (uint64(a) != lo) {
		return -1
	}
	return a
}

// add2noneng返回（x+y），除非至少有一个参数为负，或者如果
// 计算溢出int类型，则返回-1。
func add2NonNeg(x int, y int) int {
	if (x < 0) || (y < 0) {
		return -1
	}
	a := x + y
	if a < 0 {
		return -1
	}
	return a
}
